package com.EAIPClub.CodeShell.service.impl;

import com.EAIPClub.CodeShell.service.CodeShellService;
import com.EAIPClub.CodeShell.util.JschUtil;
import com.EAIPClub.CodeShell.util.SFTPConstants;
import com.api.API.CodeLab.CodeShellManager.CodeShellManagerAPI;
import com.api.API.UserAuthDataManager.UserAuthDataManagerAPI;
import com.api.API.UserDataManager.UserDataManagerAPI;
import com.api.POJO.CodeLab.CodeShell.CodeShellReturnMsg;
import com.api.POJO.CodeLab.CodeShellManager.CodeShellManagerReturnMsg;
import com.api.POJO.UserAuthDataManager.UserAuthDataManagerReturnMsg;
import com.api.POJO.UserDataManager.Result.UserDataReturnMsg;
import com.jcraft.jsch.ChannelSftp;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description :
 * @Author :
 * @Date : 2021/12/7
 */
@Service
@Slf4j
public class CodeShellServiceImpl implements CodeShellService {

    private UserAuthDataManagerAPI authDataManagerAPI;

    @Autowired
    public void setAuthDataManagerAPI(UserAuthDataManagerAPI authDataManagerAPI) {
        this.authDataManagerAPI = authDataManagerAPI;
    }

    private UserDataManagerAPI dataManagerAPI;

    @Autowired
    public void setDataManagerAPI(UserDataManagerAPI dataManagerAPI) {
        this.dataManagerAPI = dataManagerAPI;
    }

    private CodeShellManagerAPI codeShellManagerAPI;

    @Autowired
    public void setCodeShellManagerAPI(CodeShellManagerAPI codeShellManagerAPI) {
        this.codeShellManagerAPI = codeShellManagerAPI;
    }

    private JschUtil jschUtil;

    @Autowired
    public void setJschUtil(JschUtil jschUtil) {
        this.jschUtil = jschUtil;
    }

    @Override
    public CodeShellReturnMsg openCodeShell(String token) {
        CodeShellReturnMsg returnMsg = new CodeShellReturnMsg();
        List<String> Msg = new ArrayList<>();
        log.info("用户token:{}打开codeshell.", token);
        if (token == null || token.equals("")) {
            log.warn("token为空或不存在!");
            returnMsg.setStatus(500);
            Msg.add("token为空或不存在!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        log.info("开始权限鉴定.token:{}", token);
        UserAuthDataManagerReturnMsg userAuthDataByToken = authDataManagerAPI.getUserAuthDataByToken(token);
        if (userAuthDataByToken == null) {
            log.warn("通过token获取用户信息失败!返回为空.");
            returnMsg.setStatus(500);
            Msg.add("通过token获取用户信息失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }else if(userAuthDataByToken.getStatus()!=200){
            log.warn("通过token获取用户信息失败!返回:{}.",userAuthDataByToken);
            returnMsg.setStatus(500);
            Msg.add("通过token获取用户信息失败!");
            Msg.addAll(userAuthDataByToken.getMsg());
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        String uid = userAuthDataByToken.getAuthData().getUid();
        log.info("通过token获取用户信息成功.用户信息:{}",userAuthDataByToken);
        log.info("即将通过用户uid获取用户权限信息.token:{},uid:{}",token,uid);
        UserDataReturnMsg userPrivilegesByUid = dataManagerAPI.findUserPrivilegesByUid(uid);
        if (userPrivilegesByUid == null) {
            log.warn("通过uid获取用户权限信息失败!返回为空.");
            returnMsg.setStatus(500);
            Msg.add("通过uid获取用户权限信息失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }else if(userPrivilegesByUid.getStatus()!=200){
            log.warn("通过uid获取用户权限信息失败!返回:{}.",userAuthDataByToken);
            returnMsg.setStatus(500);
            Msg.add("通过uid获取用户权限信息失败!");
            Msg.addAll(userPrivilegesByUid.getMsg());
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        log.info("通过用户uid获取用户权限信息成功.权限信息:{}",userPrivilegesByUid);
        if (userPrivilegesByUid.getUserPrivileges().getCodeShell()!=1){
            log.warn("检测到该用户没有访问codeshell权限!token:{},uid:{}",token,uid);
            returnMsg.setStatus(500);
            Msg.add("您没有权限使用codeshell!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        log.info("判断该用户有使用codeshell的权限,即将申请资源.");
        CodeShellManagerReturnMsg codeShellManagerReturnMsg = codeShellManagerAPI.applyForResource(token);
        if (codeShellManagerReturnMsg==null){
            log.warn("申请资源失败!返回为空!");
            returnMsg.setStatus(500);
            Msg.add("申请资源失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }else if(codeShellManagerReturnMsg.getStatus()!=200){
            log.warn("申请资源失败!返回:{}",codeShellManagerReturnMsg);
            returnMsg.setStatus(500);
            Msg.add("申请资源失败!");
            Msg.addAll(codeShellManagerReturnMsg.getMsg());
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        log.info("申请使用资源成功!host:{}",codeShellManagerReturnMsg);
        returnMsg.setData(codeShellManagerReturnMsg.getData());
        returnMsg.setStatus(200);
        returnMsg.setMsg(Msg);
        return returnMsg;
    }

    @Override
    public CodeShellReturnMsg codeShellValidating(String token) {
        CodeShellReturnMsg returnMsg = new CodeShellReturnMsg();
        List<String> Msg = new ArrayList<>();
        log.info("开始权限鉴定.token:{}", token);
        UserAuthDataManagerReturnMsg userAuthDataByToken = authDataManagerAPI.getUserAuthDataByToken(token);
        if (userAuthDataByToken == null) {
            log.warn("通过token获取用户信息失败!返回为空.");
            returnMsg.setStatus(500);
            Msg.add("通过token获取用户信息失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }else if(userAuthDataByToken.getStatus()!=200){
            log.warn("通过token获取用户信息失败!返回:{}.",userAuthDataByToken);
            returnMsg.setStatus(500);
            Msg.add("通过token获取用户信息失败!");
            Msg.addAll(userAuthDataByToken.getMsg());
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        String uid = userAuthDataByToken.getAuthData().getUid();
        log.info("通过token获取用户信息成功.用户信息:{}",userAuthDataByToken);
        log.info("即将通过用户uid获取用户权限信息.token:{},uid:{}",token,uid);
        UserDataReturnMsg userPrivilegesByUid = dataManagerAPI.findUserPrivilegesByUid(uid);
        if (userPrivilegesByUid == null) {
            log.warn("通过uid获取用户权限信息失败!返回为空.");
            returnMsg.setStatus(500);
            Msg.add("通过uid获取用户权限信息失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }else if(userPrivilegesByUid.getStatus()!=200){
            log.warn("通过uid获取用户权限信息失败!返回:{}.",userAuthDataByToken);
            returnMsg.setStatus(500);
            Msg.add("通过uid获取用户权限信息失败!");
            Msg.addAll(userPrivilegesByUid.getMsg());
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        log.info("通过用户uid获取用户权限信息成功.权限信息:{}",userPrivilegesByUid);
        if (userPrivilegesByUid.getUserPrivileges().getCodeShell()!=1){
            log.warn("检测到该用户没有访问codeshell权限!token:{},uid:{}",token,uid);
            returnMsg.setStatus(500);
            Msg.add("您没有权限使用codeshell!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        log.info("权限鉴定成功!");
        returnMsg.setStatus(200);
        returnMsg.setMsg(Msg);
        return returnMsg;
    }

    @SneakyThrows
    @Override
    public CodeShellReturnMsg upload(String token, MultipartFile file) {
        CodeShellReturnMsg returnMsg = new CodeShellReturnMsg();
        List<String> Msg = new ArrayList<>();
        log.info("即将开始上传文件.token:{}",token);
        CodeShellManagerReturnMsg codeShellHostInfoByUserUid = codeShellManagerAPI.getCodeShellHostInfoByUserUid(token);
        if (codeShellHostInfoByUserUid==null){
            log.warn("通过用户token查找用户codeshell信息失败!返回为空!");
            returnMsg.setStatus(500);
            Msg.add("查找用户codeshell信息失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        if(codeShellHostInfoByUserUid.getStatus()!=200){
            log.warn("通过用户uid查找用户codeshell信息失败!返回信息:{}",codeShellHostInfoByUserUid.getMsg());
            returnMsg.setStatus(500);
            Msg.add("查找用户codeshell信息失败!");
            returnMsg.setMsg(Msg);
            return returnMsg;
        }
        log.info("通过用户uid查找用户codeshell信息成功.{}",codeShellHostInfoByUserUid);
        Map<String,String> sFTPInfo = new HashMap<>();
        sFTPInfo.put(SFTPConstants.SFTP_REQ_HOST,codeShellHostInfoByUserUid.getData().getHost());
        sFTPInfo.put(SFTPConstants.SFTP_REQ_PORT,codeShellHostInfoByUserUid.getData().getPort());
        sFTPInfo.put(SFTPConstants.SFTP_REQ_USERNAME,codeShellHostInfoByUserUid.getData().getUsername());
        sFTPInfo.put(SFTPConstants.SFTP_REQ_PASSWORD,codeShellHostInfoByUserUid.getData().getPassword());
        log.info("信息添加完毕,即将创建通道.{}",sFTPInfo);

        ChannelSftp channel = jschUtil.getChannel(sFTPInfo, 30000);
        String filename=file.getOriginalFilename();
        log.info("通道创建完毕,即将上传文件.");
        channel.put(file.getInputStream(),"/home/student/works"+filename);
        log.info("文件上传完毕.即将关闭通道.");
        jschUtil.closeChannel(channel);
        log.info("通道关闭完毕.本次业务结束.");
        returnMsg.setStatus(200);
        returnMsg.setMsg(Msg);
        return returnMsg;
    }
}
